package it.tukano.treditor.modules;

import it.tukano.app.AbstractAppModule;
import it.tukano.app.AppModule;
import it.tukano.check.Checks;
import it.tukano.check.Todo;
import it.tukano.reflection.MethodExt;
import it.tukano.swingdeco.controls.JPopupMenuExt;
import it.tukano.swingdeco.menubar.JMenuExt;
import it.tukano.swingdeco.menubar.JMenuItemExt;
import it.tukano.treditor.engine.geom.NTuple3;
import it.tukano.treditor.engine.scene.DirectionalLightElement;
import it.tukano.treditor.engine.scene.NodeElement;
import it.tukano.treditor.engine.scene.SceneElement;
import it.tukano.treditor.engine.scene.SceneView;
import it.tukano.treditor.resources.Labels;
import it.tukano.treditor.resources.Labels.LabelKey;
import java.awt.Color;
import java.awt.Component;
import java.awt.Point;
import java.awt.event.ActionEvent;

public class SceneGraphPopup extends AbstractAppModule {
    
    private final Labels LABELS = Labels.getInstance();
    final MethodExt listener = new MethodExt(this, "menuButtonActionPerformed", ActionEvent.class);
    final JMenuExt addMenu = new JMenuExt(LABELS.getLabelValue(LabelKey.ADD))
            .addButtons(LABELS.getLabelValue(LabelKey.NODE), LABELS.getLabelValue(LabelKey.DIRECTIONAL_LIGHT))
            .onActionPerformed(listener);
    private SceneGraphViewer sceneGraph;
    private JPopupMenuExt popup = new JPopupMenuExt().appendMenu(addMenu)
            .appendMenuItem(new JMenuItemExt(LABELS.getLabelValue(LabelKey.REMOVE)).onActionPerformed(new MethodExt(this, "removePopupElement")))
            .appendMenuItem(new JMenuItemExt(LABELS.getLabelValue(LabelKey.LOOK_AT)).onActionPerformed(new MethodExt(this, "lookAtPopupElement")));
    private DataModel dataModel;

    @Override
    public void startModule(AppModule context) {
        sceneGraph = find(SceneGraphViewer.class);
        dataModel = find(DataModel.class);
        final Component component = sceneGraph.getSceneGraphPopupHook();
        popup.bind(component, new MethodExt(this, "checkPopupCanShow", Point.class).asFunction1(Point.class, Boolean.class));
    }
    
    public Boolean checkPopupCanShow(Point atLocation) {
        SceneElement target = sceneGraph.getSceneElementAtPopupHookLocation(atLocation);
        popup.setUserObject(target);
        final SceneElement root = dataModel.getSceneRoot();
        if(root == target) {
            popup.disableButtonsLabeled(LABELS.getLabelValue(LabelKey.REMOVE));
        } else {
            popup.enableButtonsLabeled(LABELS.getLabelValue(LabelKey.REMOVE));
        }
        switch(target.getType()) {
            case NODE:
                popup.enableMenuLabeled(LABELS.getLabelValue(LabelKey.ADD));
                popup.enableMenuLabeled(LABELS.getLabelValue(LabelKey.LOOK_AT));
                break;
            default:
                popup.disableMenuLabeled(LABELS.getLabelValue(LabelKey.ADD));
                popup.disableMenuLabeled(LABELS.getLabelValue(LabelKey.LOOK_AT));
                Todo.implementThis("popup for element ", target.getType());
        }
        return target != null;
    }
    
    public void removePopupElement() {
        final SceneElement sceneRoot = dataModel.getSceneRoot();
        final Object userObject = popup.getUserObject();
        final Point popupPoint = popup.getLastPopupLocation();
        Checks.True(userObject != sceneRoot);
        Checks.True(userObject instanceof SceneElement);
        final SceneElement element = (SceneElement) userObject;
        sceneGraph.removeElement(element);
    }
    
    public void lookAtPopupElement() {
        Object userObject = popup.getUserObject();
        Checks.True(userObject instanceof SceneElement);
        final SceneElement element = (SceneElement) userObject;
        final SceneView view = dataModel.getCurrentView();
        dataModel.setCurrentViewToLookAtElement(this, element);
    }

    public void menuButtonActionPerformed(ActionEvent e) {
        final Object userObject = popup.getUserObject();
        final Point popupPoint = popup.getLastPopupLocation();
        final String actionCommand = e.getActionCommand();
        
        Checks.NotNull(userObject);
        Checks.NotNull(popupPoint);
        Checks.InstanceOf(userObject, SceneElement.class);
        
        final SceneElement boundElement = (SceneElement) userObject;
        final boolean targetElementIsNode = boundElement.getType() == SceneElement.Type.NODE;
        final boolean addNode = LABELS.getLabelValue(LabelKey.NODE).equals(actionCommand);
        final boolean addDirectionalLight = LABELS.getLabelValue(LabelKey.DIRECTIONAL_LIGHT).equals(actionCommand);
        
        if(targetElementIsNode && addNode) {
            addNodeToNode((NodeElement) boundElement);
        } else if(targetElementIsNode && addDirectionalLight) {
            addDirectionaLightToNode((NodeElement) boundElement);
        } else {
            Todo.implementThis();
        }
    }

    private void addNodeToNode(NodeElement nodeElement) {
        NodeElement newNode = new NodeElement();
        newNode.setName(LABELS.getLabelValue(LabelKey.NEW_NODE_NAME));
        nodeElement.addChild(newNode);
        dataModel.notifyEmptyNodeAddToNode(this, newNode, nodeElement);
    }

    private void addDirectionaLightToNode(NodeElement nodeElement) {
        System.out.println("directional light added to node");
        DirectionalLightElement light = new DirectionalLightElement();
        light.setColor(Color.WHITE);
        light.setDirection(new NTuple3(-1, -1, -1));
        nodeElement.addChild(light);
        dataModel.notifyDirectionalLightAddToNode(this, light, nodeElement);
    }
}
